Debug mode for unordered_set. I believe this to be fairly complete for unordered_set, however it is not complete yet for unordered_multiset, unordered_map or unordered_multimap. There has been a lot of work done for these other three containers, however that work was done just to keep all of the tests passing. You can try this out with -D_LIBCPP_DEBUG2. You will have to link to a libc++.dylib that has been compiled with src/debug.cpp. So far, vector (but not vector<bool>), list, and unordered_set are treated. I hope to get the other three unordered containers up fairly quickly now that unordered_set is done. The flag _LIBCPP_DEBUG2 will eventually be changed to _LIBCPP_DEBUG, but not today. This is my second effort at getting debug mode going for libc++, and I'm not quite yet ready to throw all of the work under the first attempt away. The basic design is that all of the debug information is kept in a central database, instead of in the containers. This has been done as an attempt to have debug mode and non-debug mode be ABI compatible with each other. There are some circumstances where if you construct a container in an environment without debug mode and pass it into debug mode, the checking will get confused and let you know with a readable error message. Passing containers the other way: from debug mode out to a non-debugging mode container should be 100% safe (at least that is the goal). git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@186991 91177308-0d34-0410-b5e6-96231b3b80d8 
diff --git a/include/__hash_table b/include/__hash_table index 2b282d3..55398e4 100644 --- a/include/__hash_table +++ b/include/__hash_table 
@@ -105,16 +105,67 @@  #endif  pointer;   - _LIBCPP_INLINE_VISIBILITY __hash_iterator() _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY __hash_iterator() _NOEXCEPT + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_i(this); +#endif + } + +#if _LIBCPP_DEBUG_LEVEL >= 2    _LIBCPP_INLINE_VISIBILITY - reference operator*() const {return __node_->__value_;} + __hash_iterator(const __hash_iterator& __i) + : __node_(__i.__node_) + { + __get_db()->__iterator_copy(this, &__i); + } +  _LIBCPP_INLINE_VISIBILITY - pointer operator->() const {return pointer_traits<pointer>::pointer_to(__node_->__value_);} + ~__hash_iterator() + { + __get_db()->__erase_i(this); + } + + _LIBCPP_INLINE_VISIBILITY + __hash_iterator& operator=(const __hash_iterator& __i) + { + if (this != &__i) + { + __get_db()->__iterator_copy(this, &__i); + __node_ = __i.__node_; + } + return *this; + } + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 + + _LIBCPP_INLINE_VISIBILITY + reference operator*() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container iterator"); +#endif + return __node_->__value_; + } + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container iterator"); +#endif + return pointer_traits<pointer>::pointer_to(__node_->__value_); + }    _LIBCPP_INLINE_VISIBILITY  __hash_iterator& operator++()  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to increment non-incrementable unordered container iterator"); +#endif  __node_ = __node_->__next_;  return *this;  } @@ -129,16 +180,31 @@    friend _LIBCPP_INLINE_VISIBILITY  bool operator==(const __hash_iterator& __x, const __hash_iterator& __y) - {return __x.__node_ == __y.__node_;} + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y), + "Attempted to compare non-comparable unordered container iterator"); +#endif + return __x.__node_ == __y.__node_; + }  friend _LIBCPP_INLINE_VISIBILITY  bool operator!=(const __hash_iterator& __x, const __hash_iterator& __y) - {return __x.__node_ != __y.__node_;} + {return !(__x == __y);}    private: +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_INLINE_VISIBILITY + __hash_iterator(__node_pointer __node, const void* __c) _NOEXCEPT + : __node_(__node) + { + __get_db()->__insert_ic(this, __c); + } +#else  _LIBCPP_INLINE_VISIBILITY  __hash_iterator(__node_pointer __node) _NOEXCEPT  : __node_(__node)  {} +#endif    template <class, class, class, class> friend class __hash_table;  template <class> friend class _LIBCPP_TYPE_VIS __hash_const_iterator; @@ -179,20 +245,75 @@  __non_const_node_pointer;  typedef __hash_iterator<__non_const_node_pointer> __non_const_iterator;   - _LIBCPP_INLINE_VISIBILITY __hash_const_iterator() _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY __hash_const_iterator() _NOEXCEPT + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_i(this); +#endif + }  _LIBCPP_INLINE_VISIBILITY   __hash_const_iterator(const __non_const_iterator& __x) _NOEXCEPT  : __node_(__x.__node_) - {} + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__iterator_copy(this, &__x); +#endif + } + +#if _LIBCPP_DEBUG_LEVEL >= 2    _LIBCPP_INLINE_VISIBILITY - reference operator*() const {return __node_->__value_;} + __hash_const_iterator(const __hash_const_iterator& __i) + : __node_(__i.__node_) + { + __get_db()->__iterator_copy(this, &__i); + } +  _LIBCPP_INLINE_VISIBILITY - pointer operator->() const {return pointer_traits<pointer>::pointer_to(__node_->__value_);} + ~__hash_const_iterator() + { + __get_db()->__erase_i(this); + } + + _LIBCPP_INLINE_VISIBILITY + __hash_const_iterator& operator=(const __hash_const_iterator& __i) + { + if (this != &__i) + { + __get_db()->__iterator_copy(this, &__i); + __node_ = __i.__node_; + } + return *this; + } + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 + + _LIBCPP_INLINE_VISIBILITY + reference operator*() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container const_iterator"); +#endif + return __node_->__value_; + } + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container const_iterator"); +#endif + return pointer_traits<pointer>::pointer_to(__node_->__value_); + }    _LIBCPP_INLINE_VISIBILITY  __hash_const_iterator& operator++()  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to increment non-incrementable unordered container const_iterator"); +#endif  __node_ = __node_->__next_;  return *this;  } @@ -207,16 +328,31 @@    friend _LIBCPP_INLINE_VISIBILITY  bool operator==(const __hash_const_iterator& __x, const __hash_const_iterator& __y) - {return __x.__node_ == __y.__node_;} + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y), + "Attempted to compare non-comparable unordered container const_iterator"); +#endif + return __x.__node_ == __y.__node_; + }  friend _LIBCPP_INLINE_VISIBILITY  bool operator!=(const __hash_const_iterator& __x, const __hash_const_iterator& __y) - {return __x.__node_ != __y.__node_;} + {return !(__x == __y);}    private: +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_INLINE_VISIBILITY + __hash_const_iterator(__node_pointer __node, const void* __c) _NOEXCEPT + : __node_(__node) + { + __get_db()->__insert_ic(this, __c); + } +#else  _LIBCPP_INLINE_VISIBILITY  __hash_const_iterator(__node_pointer __node) _NOEXCEPT  : __node_(__node)  {} +#endif    template <class, class, class, class> friend class __hash_table;  template <class> friend class _LIBCPP_TYPE_VIS __hash_map_const_iterator; @@ -249,16 +385,71 @@  #endif  pointer;   - _LIBCPP_INLINE_VISIBILITY __hash_local_iterator() _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY __hash_local_iterator() _NOEXCEPT + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_i(this); +#endif + } + +#if _LIBCPP_DEBUG_LEVEL >= 2    _LIBCPP_INLINE_VISIBILITY - reference operator*() const {return __node_->__value_;} + __hash_local_iterator(const __hash_local_iterator& __i) + : __node_(__i.__node_), + __bucket_(__i.__bucket_), + __bucket_count_(__i.__bucket_count_) + { + __get_db()->__iterator_copy(this, &__i); + } +  _LIBCPP_INLINE_VISIBILITY - pointer operator->() const {return pointer_traits<pointer>::pointer_to(__node_->__value_);} + ~__hash_local_iterator() + { + __get_db()->__erase_i(this); + } + + _LIBCPP_INLINE_VISIBILITY + __hash_local_iterator& operator=(const __hash_local_iterator& __i) + { + if (this != &__i) + { + __get_db()->__iterator_copy(this, &__i); + __node_ = __i.__node_; + __bucket_ = __i.__bucket_; + __bucket_count_ = __i.__bucket_count_; + } + return *this; + } + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 + + _LIBCPP_INLINE_VISIBILITY + reference operator*() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container local_iterator"); +#endif + return __node_->__value_; + } + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container local_iterator"); +#endif + return pointer_traits<pointer>::pointer_to(__node_->__value_); + }    _LIBCPP_INLINE_VISIBILITY  __hash_local_iterator& operator++()  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to increment non-incrementable unordered container local_iterator"); +#endif  __node_ = __node_->__next_;  if (__node_ != nullptr && __constrain_hash(__node_->__hash_, __bucket_count_) != __bucket_)  __node_ = nullptr; @@ -275,12 +466,31 @@    friend _LIBCPP_INLINE_VISIBILITY  bool operator==(const __hash_local_iterator& __x, const __hash_local_iterator& __y) - {return __x.__node_ == __y.__node_;} + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y), + "Attempted to compare non-comparable unordered container local_iterator"); +#endif + return __x.__node_ == __y.__node_; + }  friend _LIBCPP_INLINE_VISIBILITY  bool operator!=(const __hash_local_iterator& __x, const __hash_local_iterator& __y) - {return __x.__node_ != __y.__node_;} + {return !(__x == __y);}    private: +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_INLINE_VISIBILITY + __hash_local_iterator(__node_pointer __node, size_t __bucket, + size_t __bucket_count, const void* __c) _NOEXCEPT + : __node_(__node), + __bucket_(__bucket), + __bucket_count_(__bucket_count) + { + __get_db()->__insert_ic(this, __c); + if (__node_ != nullptr) + __node_ = __node_->__next_; + } +#else  _LIBCPP_INLINE_VISIBILITY  __hash_local_iterator(__node_pointer __node, size_t __bucket,  size_t __bucket_count) _NOEXCEPT @@ -291,7 +501,7 @@  if (__node_ != nullptr)  __node_ = __node_->__next_;  } - +#endif  template <class, class, class, class> friend class __hash_table;  template <class> friend class _LIBCPP_TYPE_VIS __hash_const_local_iterator;  template <class> friend class _LIBCPP_TYPE_VIS __hash_map_iterator; @@ -333,22 +543,82 @@  #endif  pointer;   - _LIBCPP_INLINE_VISIBILITY __hash_const_local_iterator() _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY __hash_const_local_iterator() _NOEXCEPT + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_i(this); +#endif + } +  _LIBCPP_INLINE_VISIBILITY  __hash_const_local_iterator(const __non_const_iterator& __x) _NOEXCEPT  : __node_(__x.__node_),  __bucket_(__x.__bucket_),  __bucket_count_(__x.__bucket_count_) - {} + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__iterator_copy(this, &__x); +#endif + } + +#if _LIBCPP_DEBUG_LEVEL >= 2    _LIBCPP_INLINE_VISIBILITY - reference operator*() const {return __node_->__value_;} + __hash_const_local_iterator(const __hash_const_local_iterator& __i) + : __node_(__i.__node_), + __bucket_(__i.__bucket_), + __bucket_count_(__i.__bucket_count_) + { + __get_db()->__iterator_copy(this, &__i); + } +  _LIBCPP_INLINE_VISIBILITY - pointer operator->() const {return pointer_traits<pointer>::pointer_to(__node_->__value_);} + ~__hash_const_local_iterator() + { + __get_db()->__erase_i(this); + } + + _LIBCPP_INLINE_VISIBILITY + __hash_const_local_iterator& operator=(const __hash_const_local_iterator& __i) + { + if (this != &__i) + { + __get_db()->__iterator_copy(this, &__i); + __node_ = __i.__node_; + __bucket_ = __i.__bucket_; + __bucket_count_ = __i.__bucket_count_; + } + return *this; + } + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 + + _LIBCPP_INLINE_VISIBILITY + reference operator*() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container const_local_iterator"); +#endif + return __node_->__value_; + } + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to dereference a non-dereferenceable unordered container const_local_iterator"); +#endif + return pointer_traits<pointer>::pointer_to(__node_->__value_); + }    _LIBCPP_INLINE_VISIBILITY  __hash_const_local_iterator& operator++()  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this), + "Attempted to increment non-incrementable unordered container const_local_iterator"); +#endif  __node_ = __node_->__next_;  if (__node_ != nullptr && __constrain_hash(__node_->__hash_, __bucket_count_) != __bucket_)  __node_ = nullptr; @@ -365,12 +635,31 @@    friend _LIBCPP_INLINE_VISIBILITY  bool operator==(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y) - {return __x.__node_ == __y.__node_;} + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y), + "Attempted to compare non-comparable unordered container local_const_iterator"); +#endif + return __x.__node_ == __y.__node_; + }  friend _LIBCPP_INLINE_VISIBILITY  bool operator!=(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y) - {return __x.__node_ != __y.__node_;} + {return !(__x == __y);}    private: +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_INLINE_VISIBILITY + __hash_const_local_iterator(__node_pointer __node, size_t __bucket, + size_t __bucket_count, const void* __c) _NOEXCEPT + : __node_(__node), + __bucket_(__bucket), + __bucket_count_(__bucket_count) + { + __get_db()->__insert_ic(this, __c); + if (__node_ != nullptr) + __node_ = __node_->__next_; + } +#else  _LIBCPP_INLINE_VISIBILITY  __hash_const_local_iterator(__node_pointer __node, size_t __bucket,  size_t __bucket_count) _NOEXCEPT @@ -381,7 +670,7 @@  if (__node_ != nullptr)  __node_ = __node_->__next_;  } - +#endif  template <class, class, class, class> friend class __hash_table;  template <class> friend class _LIBCPP_TYPE_VIS __hash_map_const_iterator;  }; @@ -722,14 +1011,59 @@  _LIBCPP_INLINE_VISIBILITY void max_load_factor(float __mlf) _NOEXCEPT  {max_load_factor() = _VSTD::max(__mlf, load_factor());}   - _LIBCPP_INLINE_VISIBILITY local_iterator begin(size_type __n) - {return local_iterator(__bucket_list_[__n], __n, bucket_count());} - _LIBCPP_INLINE_VISIBILITY local_iterator end(size_type __n) - {return local_iterator(nullptr, __n, bucket_count());} - _LIBCPP_INLINE_VISIBILITY const_local_iterator cbegin(size_type __n) const - {return const_local_iterator(__bucket_list_[__n], __n, bucket_count());} - _LIBCPP_INLINE_VISIBILITY const_local_iterator cend(size_type __n) const - {return const_local_iterator(nullptr, __n, bucket_count());} + _LIBCPP_INLINE_VISIBILITY + local_iterator + begin(size_type __n) + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return local_iterator(__bucket_list_[__n], __n, bucket_count(), this); +#else + return local_iterator(__bucket_list_[__n], __n, bucket_count()); +#endif + } + + _LIBCPP_INLINE_VISIBILITY + local_iterator + end(size_type __n) + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return local_iterator(nullptr, __n, bucket_count(), this); +#else + return local_iterator(nullptr, __n, bucket_count()); +#endif + } + + _LIBCPP_INLINE_VISIBILITY + const_local_iterator + cbegin(size_type __n) const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return const_local_iterator(__bucket_list_[__n], __n, bucket_count(), this); +#else + return const_local_iterator(__bucket_list_[__n], __n, bucket_count()); +#endif + } + + _LIBCPP_INLINE_VISIBILITY + const_local_iterator + cend(size_type __n) const + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return const_local_iterator(nullptr, __n, bucket_count(), this); +#else + return const_local_iterator(nullptr, __n, bucket_count()); +#endif + } + +#if _LIBCPP_DEBUG_LEVEL >= 2 + + bool __dereferenceable(const const_iterator* __i) const; + bool __decrementable(const const_iterator* __i) const; + bool __addable(const const_iterator* __i, ptrdiff_t __n) const; + bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const; + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 +  private:  void __rehash(size_type __n);   @@ -939,6 +1273,9 @@  __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table()  {  __deallocate(__p1_.first().__next_); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__erase_c(this); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -980,6 +1317,21 @@  while (__np != nullptr)  {  __node_pointer __next = __np->__next_; +#if _LIBCPP_DEBUG_LEVEL >= 2 + __c_node* __c = __get_db()->__find_c_and_lock(this); + for (__i_node** __p = __c->end_; __p != __c->beg_; ) + { + --__p; + iterator* __i = static_cast<iterator*>((*__p)->__i_); + if (__i->__node_ == __np) + { + (*__p)->__c_ = nullptr; + if (--__c->end_ != __p) + memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*)); + } + } + __get_db()->unlock(); +#endif  __node_traits::destroy(__na, _VSTD::addressof(__np->__value_));  __node_traits::deallocate(__na, __np, 1);  __np = __next; @@ -1027,6 +1379,9 @@  __u.__p1_.first().__next_ = nullptr;  __u.size() = 0;  } +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->swap(this, &__u); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1167,7 +1522,11 @@  typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator  __hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() _NOEXCEPT  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return iterator(__p1_.first().__next_, this); +#else  return iterator(__p1_.first().__next_); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1175,7 +1534,11 @@  typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator  __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() _NOEXCEPT  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return iterator(nullptr, this); +#else  return iterator(nullptr); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1183,7 +1546,11 @@  typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator  __hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const _NOEXCEPT  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return const_iterator(__p1_.first().__next_, this); +#else  return const_iterator(__p1_.first().__next_); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1191,7 +1558,11 @@  typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator  __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + return const_iterator(nullptr, this); +#else  return const_iterator(nullptr); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1264,7 +1635,11 @@  __inserted = true;  }  __done: +#if _LIBCPP_DEBUG_LEVEL >= 2 + return pair<iterator, bool>(iterator(__ndptr, this), __inserted); +#else  return pair<iterator, bool>(iterator(__ndptr), __inserted); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1321,7 +1696,11 @@  }  }  ++size(); +#if _LIBCPP_DEBUG_LEVEL >= 2 + return iterator(__cp, this); +#else  return iterator(__cp); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1347,7 +1726,11 @@  __cp->__next_ = __np;  __pp->__next_ = __cp;  ++size(); +#if _LIBCPP_DEBUG_LEVEL >= 2 + return iterator(__cp, this); +#else  return iterator(__cp); +#endif  }  return __node_insert_multi(__cp);  } @@ -1408,7 +1791,11 @@  __inserted = true;  }  __done: +#if _LIBCPP_DEBUG_LEVEL >= 2 + return pair<iterator, bool>(iterator(__nd, this), __inserted); +#else  return pair<iterator, bool>(iterator(__nd), __inserted); +#endif  }    #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -1543,6 +1930,9 @@  void  __hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __nbc)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__invalidate_all(this); +#endif // _LIBCPP_DEBUG_LEVEL >= 2  __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc();  __bucket_list_.reset(__nbc > 0 ?  __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr); @@ -1608,7 +1998,11 @@  __nd = __nd->__next_)  {  if (key_eq()(__nd->__value_, __k)) +#if _LIBCPP_DEBUG_LEVEL >= 2 + return iterator(__nd, this); +#else  return iterator(__nd); +#endif  }  }  } @@ -1633,7 +2027,11 @@  __nd = __nd->__next_)  {  if (key_eq()(__nd->__value_, __k)) +#if _LIBCPP_DEBUG_LEVEL >= 2 + return const_iterator(__nd, this); +#else  return const_iterator(__nd); +#endif  }  }   @@ -1710,7 +2108,16 @@  __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p)  {  __node_pointer __np = __p.__node_; +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this, + "unordered container erase(iterator) called with an iterator not" + " referring to this container"); + _LIBCPP_ASSERT(__p != end(), + "unordered container erase(iterator) called with a non-dereferenceable iterator"); + iterator __r(__np, this); +#else  iterator __r(__np); +#endif  ++__r;  remove(__p);  return __r; @@ -1721,13 +2128,25 @@  __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first,  const_iterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__first) == this, + "unodered container::erase(iterator, iterator) called with an iterator not" + " referring to this unodered container"); + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__last) == this, + "unodered container::erase(iterator, iterator) called with an iterator not" + " referring to this unodered container"); +#endif  for (const_iterator __p = __first; __first != __last; __p = __first)  {  ++__first;  erase(__p);  }  __node_pointer __np = __last.__node_; +#if _LIBCPP_DEBUG_LEVEL >= 2 + return iterator (__np, this); +#else  return iterator (__np); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1793,6 +2212,21 @@  __pn->__next_ = __cn->__next_;  __cn->__next_ = nullptr;  --size(); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __c_node* __c = __get_db()->__find_c_and_lock(this); + for (__i_node** __p = __c->end_; __p != __c->beg_; ) + { + --__p; + iterator* __i = static_cast<iterator*>((*__p)->__i_); + if (__i->__node_ == __cn) + { + (*__p)->__c_ = nullptr; + if (--__c->end_ != __p) + memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*)); + } + } + __get_db()->unlock(); +#endif  return __node_holder(__cn, _Dp(__node_alloc(), true));  }   @@ -1921,6 +2355,9 @@  if (__u.size() > 0)  __u.__bucket_list_[__constrain_hash(__u.__p1_.first().__next_->__hash_, __u.bucket_count())] =  static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__u.__p1_.first())); +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->swap(this, &__u); +#endif  }    template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1950,6 +2387,37 @@  __x.swap(__y);  }   +#if _LIBCPP_DEBUG_LEVEL >= 2 + +template <class _Tp, class _Hash, class _Equal, class _Alloc> +bool +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__dereferenceable(const const_iterator* __i) const +{ + return __i->__node_ != nullptr; +} + +template <class _Tp, class _Hash, class _Equal, class _Alloc> +bool +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__decrementable(const const_iterator*) const +{ + return false; +} + +template <class _Tp, class _Hash, class _Equal, class _Alloc> +bool +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__addable(const const_iterator*, ptrdiff_t) const +{ + return false; +} + +template <class _Tp, class _Hash, class _Equal, class _Alloc> +bool +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__subscriptable(const const_iterator*, ptrdiff_t) const +{ + return false; +} + +#endif // _LIBCPP_DEBUG_LEVEL >= 2  _LIBCPP_END_NAMESPACE_STD    #endif // _LIBCPP__HASH_TABLE 
diff --git a/include/unordered_map b/include/unordered_map index 78e6307..55db2f5 100644 --- a/include/unordered_map +++ b/include/unordered_map 
@@ -624,6 +624,8 @@  typedef pair<key_type, mapped_type> __nc_value_type;  typedef value_type& reference;  typedef const value_type& const_reference; + static_assert((is_same<value_type, typename allocator_type::value_type>::value), + "Invalid allocator::value_type");    private:  #if __cplusplus >= 201103L @@ -706,7 +708,11 @@  _LIBCPP_INLINE_VISIBILITY  unordered_map()  _NOEXCEPT_(is_nothrow_default_constructible<__table>::value) - {} // = default; + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif + }  explicit unordered_map(size_type __n, const hasher& __hf = hasher(),  const key_equal& __eql = key_equal());  unordered_map(size_type __n, const hasher& __hf, @@ -905,6 +911,19 @@  _LIBCPP_INLINE_VISIBILITY  void reserve(size_type __n) {__table_.reserve(__n);}   +#if _LIBCPP_DEBUG_LEVEL >= 2 + + bool __dereferenceable(const const_iterator* __i) const + {return __table_.__dereferenceable(&__i->__i_);} + bool __decrementable(const const_iterator* __i) const + {return __table_.__decrementable(&__i->__i_);} + bool __addable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(&__i->__i_, __n);} + bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(&__i->__i_, __n);} + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 +  private:  #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES  __node_holder __construct_node(); @@ -925,6 +944,9 @@  size_type __n, const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -934,6 +956,9 @@  const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -943,6 +968,9 @@  const allocator_type& __a)  : __table_(__a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> @@ -950,6 +978,9 @@  unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(  _InputIterator __first, _InputIterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__first, __last);  }   @@ -960,6 +991,9 @@  const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -971,6 +1005,9 @@  const hasher& __hf, const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -980,6 +1017,9 @@  const unordered_map& __u)  : __table_(__u.__table_)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -989,6 +1029,9 @@  const unordered_map& __u, const allocator_type& __a)  : __table_(__u.__table_, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -1002,6 +1045,9 @@  _NOEXCEPT_(is_nothrow_move_constructible<__table>::value)  : __table_(_VSTD::move(__u.__table_))  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> @@ -1009,6 +1055,9 @@  unordered_map&& __u, const allocator_type& __a)  : __table_(_VSTD::move(__u.__table_), __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  if (__a != __u.get_allocator())  {  iterator __i = __u.begin(); @@ -1027,6 +1076,9 @@  unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(  initializer_list<value_type> __il)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__il.begin(), __il.end());  }   @@ -1036,6 +1088,9 @@  const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  } @@ -1046,6 +1101,9 @@  const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  } @@ -1286,6 +1344,8 @@  typedef pair<key_type, mapped_type> __nc_value_type;  typedef value_type& reference;  typedef const value_type& const_reference; + static_assert((is_same<value_type, typename allocator_type::value_type>::value), + "Invalid allocator::value_type");    private:  #if __cplusplus >= 201103L @@ -1366,7 +1426,11 @@  _LIBCPP_INLINE_VISIBILITY  unordered_multimap()  _NOEXCEPT_(is_nothrow_default_constructible<__table>::value) - {} // = default; + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif + }  explicit unordered_multimap(size_type __n, const hasher& __hf = hasher(),  const key_equal& __eql = key_equal());  unordered_multimap(size_type __n, const hasher& __hf, @@ -1556,6 +1620,19 @@  _LIBCPP_INLINE_VISIBILITY  void reserve(size_type __n) {__table_.reserve(__n);}   +#if _LIBCPP_DEBUG_LEVEL >= 2 + + bool __dereferenceable(const const_iterator* __i) const + {return __table_.__dereferenceable(&__i->__i_);} + bool __decrementable(const const_iterator* __i) const + {return __table_.__decrementable(&__i->__i_);} + bool __addable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(&__i->__i_, __n);} + bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(&__i->__i_, __n);} + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 +  private:  #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES  __node_holder __construct_node(); @@ -1574,6 +1651,9 @@  size_type __n, const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -1583,6 +1663,9 @@  const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -1591,6 +1674,9 @@  unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(  _InputIterator __first, _InputIterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__first, __last);  }   @@ -1601,6 +1687,9 @@  const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -1612,6 +1701,9 @@  const hasher& __hf, const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -1622,6 +1714,9 @@  const allocator_type& __a)  : __table_(__a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> @@ -1629,6 +1724,9 @@  const unordered_multimap& __u)  : __table_(__u.__table_)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -1638,6 +1736,9 @@  const unordered_multimap& __u, const allocator_type& __a)  : __table_(__u.__table_, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -1651,6 +1752,9 @@  _NOEXCEPT_(is_nothrow_move_constructible<__table>::value)  : __table_(_VSTD::move(__u.__table_))  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> @@ -1658,15 +1762,18 @@  unordered_multimap&& __u, const allocator_type& __a)  : __table_(_VSTD::move(__u.__table_), __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  if (__a != __u.get_allocator())  {  iterator __i = __u.begin();  while (__u.size() != 0) -{ + {  __table_.__insert_multi(  _VSTD::move(__u.__table_.remove((__i++).__i_)->__value_)  ); -} + }  }  }   @@ -1678,6 +1785,9 @@  unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(  initializer_list<value_type> __il)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__il.begin(), __il.end());  }   @@ -1687,6 +1797,9 @@  const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  } @@ -1697,6 +1810,9 @@  const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  } 
diff --git a/include/unordered_set b/include/unordered_set index 119251d..8be36df 100644 --- a/include/unordered_set +++ b/include/unordered_set 
@@ -324,6 +324,8 @@  typedef _Alloc allocator_type;  typedef value_type& reference;  typedef const value_type& const_reference; + static_assert((is_same<value_type, typename allocator_type::value_type>::value), + "Invalid allocator::value_type");    private:  typedef __hash_table<value_type, hasher, key_equal, allocator_type> __table; @@ -344,7 +346,11 @@  _LIBCPP_INLINE_VISIBILITY  unordered_set()  _NOEXCEPT_(is_nothrow_default_constructible<__table>::value) - {} // = default; + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif + }  explicit unordered_set(size_type __n, const hasher& __hf = hasher(),  const key_equal& __eql = key_equal());  unordered_set(size_type __n, const hasher& __hf, const key_equal& __eql, @@ -422,8 +428,18 @@  {return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...);}  template <class... _Args>  _LIBCPP_INLINE_VISIBILITY +#if _LIBCPP_DEBUG_LEVEL >= 2 + iterator emplace_hint(const_iterator __p, _Args&&... __args) + { + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this, + "unordered_set::emplace_hint(const_iterator, args...) called with an iterator not" + " referring to this unordered_set"); + return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...).first; + } +#else  iterator emplace_hint(const_iterator, _Args&&... __args)  {return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...).first;} +#endif  #endif // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)  _LIBCPP_INLINE_VISIBILITY  pair<iterator, bool> insert(const value_type& __x) @@ -434,12 +450,32 @@  {return __table_.__insert_unique(_VSTD::move(__x));}  #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES  _LIBCPP_INLINE_VISIBILITY +#if _LIBCPP_DEBUG_LEVEL >= 2 + iterator insert(const_iterator __p, const value_type& __x) + { + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this, + "unordered_set::insert(const_iterator, const value_type&) called with an iterator not" + " referring to this unordered_set"); + return insert(__x).first; + } +#else  iterator insert(const_iterator, const value_type& __x)  {return insert(__x).first;} +#endif  #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES  _LIBCPP_INLINE_VISIBILITY +#if _LIBCPP_DEBUG_LEVEL >= 2 + iterator insert(const_iterator __p, value_type&& __x) + { + _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this, + "unordered_set::insert(const_iterator, value_type&&) called with an iterator not" + " referring to this unordered_set"); + return insert(_VSTD::move(__x)).first; + } +#else  iterator insert(const_iterator, value_type&& __x)  {return insert(_VSTD::move(__x)).first;} +#endif  #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES  template <class _InputIterator>  void insert(_InputIterator __first, _InputIterator __last); @@ -515,6 +551,20 @@  void rehash(size_type __n) {__table_.rehash(__n);}  _LIBCPP_INLINE_VISIBILITY  void reserve(size_type __n) {__table_.reserve(__n);} + +#if _LIBCPP_DEBUG_LEVEL >= 2 + + bool __dereferenceable(const const_iterator* __i) const + {return __table_.__dereferenceable(__i);} + bool __decrementable(const const_iterator* __i) const + {return __table_.__decrementable(__i);} + bool __addable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(__i, __n);} + bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(__i, __n);} + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 +  };    template <class _Value, class _Hash, class _Pred, class _Alloc> @@ -522,6 +572,9 @@  const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -530,6 +583,9 @@  const hasher& __hf, const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -538,6 +594,9 @@  unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(  _InputIterator __first, _InputIterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__first, __last);  }   @@ -548,6 +607,9 @@  const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -559,6 +621,9 @@  const hasher& __hf, const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -569,6 +634,9 @@  const allocator_type& __a)  : __table_(__a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _Value, class _Hash, class _Pred, class _Alloc> @@ -576,6 +644,9 @@  const unordered_set& __u)  : __table_(__u.__table_)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -585,6 +656,9 @@  const unordered_set& __u, const allocator_type& __a)  : __table_(__u.__table_, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -598,6 +672,10 @@  _NOEXCEPT_(is_nothrow_move_constructible<__table>::value)  : __table_(_VSTD::move(__u.__table_))  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); + __get_db()->swap(this, &__u); +#endif  }    template <class _Value, class _Hash, class _Pred, class _Alloc> @@ -605,12 +683,19 @@  unordered_set&& __u, const allocator_type& __a)  : __table_(_VSTD::move(__u.__table_), __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  if (__a != __u.get_allocator())  {  iterator __i = __u.begin();  while (__u.size() != 0)  __table_.__insert_unique(_VSTD::move(__u.__table_.remove(__i++)->__value_));  } +#if _LIBCPP_DEBUG_LEVEL >= 2 + else + __get_db()->swap(this, &__u); +#endif  }    #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -621,6 +706,9 @@  unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(  initializer_list<value_type> __il)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__il.begin(), __il.end());  }   @@ -630,6 +718,9 @@  const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  } @@ -640,6 +731,9 @@  const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  } @@ -736,6 +830,8 @@  typedef _Alloc allocator_type;  typedef value_type& reference;  typedef const value_type& const_reference; + static_assert((is_same<value_type, typename allocator_type::value_type>::value), + "Invalid allocator::value_type");    private:  typedef __hash_table<value_type, hasher, key_equal, allocator_type> __table; @@ -756,7 +852,11 @@  _LIBCPP_INLINE_VISIBILITY  unordered_multiset()  _NOEXCEPT_(is_nothrow_default_constructible<__table>::value) - {} // = default + { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif + }  explicit unordered_multiset(size_type __n, const hasher& __hf = hasher(),  const key_equal& __eql = key_equal());  unordered_multiset(size_type __n, const hasher& __hf, @@ -925,6 +1025,20 @@  void rehash(size_type __n) {__table_.rehash(__n);}  _LIBCPP_INLINE_VISIBILITY  void reserve(size_type __n) {__table_.reserve(__n);} + +#if _LIBCPP_DEBUG_LEVEL >= 2 + + bool __dereferenceable(const const_iterator* __i) const + {return __table_.__dereferenceable(__i);} + bool __decrementable(const const_iterator* __i) const + {return __table_.__decrementable(__i);} + bool __addable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(__i, __n);} + bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const + {return __table_.__addable(__i, __n);} + +#endif // _LIBCPP_DEBUG_LEVEL >= 2 +  };    template <class _Value, class _Hash, class _Pred, class _Alloc> @@ -932,6 +1046,9 @@  size_type __n, const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -941,6 +1058,9 @@  const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  }   @@ -949,6 +1069,9 @@  unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(  _InputIterator __first, _InputIterator __last)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__first, __last);  }   @@ -959,6 +1082,9 @@  const hasher& __hf, const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -970,6 +1096,9 @@  const hasher& __hf, const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__first, __last);  } @@ -980,6 +1109,9 @@  const allocator_type& __a)  : __table_(__a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  }    template <class _Value, class _Hash, class _Pred, class _Alloc> @@ -987,6 +1119,9 @@  const unordered_multiset& __u)  : __table_(__u.__table_)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -996,6 +1131,9 @@  const unordered_multiset& __u, const allocator_type& __a)  : __table_(__u.__table_, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__u.bucket_count());  insert(__u.begin(), __u.end());  } @@ -1009,6 +1147,10 @@  _NOEXCEPT_(is_nothrow_move_constructible<__table>::value)  : __table_(_VSTD::move(__u.__table_))  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); + __get_db()->swap(this, &__u); +#endif  }    template <class _Value, class _Hash, class _Pred, class _Alloc> @@ -1016,12 +1158,19 @@  unordered_multiset&& __u, const allocator_type& __a)  : __table_(_VSTD::move(__u.__table_), __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  if (__a != __u.get_allocator())  {  iterator __i = __u.begin();  while (__u.size() != 0)  __table_.__insert_multi(_VSTD::move(__u.__table_.remove(__i++)->__value_));  } +#if _LIBCPP_DEBUG_LEVEL >= 2 + else + __get_db()->swap(this, &__u); +#endif  }    #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -1032,6 +1181,9 @@  unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(  initializer_list<value_type> __il)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  insert(__il.begin(), __il.end());  }   @@ -1041,6 +1193,9 @@  const key_equal& __eql)  : __table_(__hf, __eql)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  } @@ -1051,6 +1206,9 @@  const key_equal& __eql, const allocator_type& __a)  : __table_(__hf, __eql, __a)  { +#if _LIBCPP_DEBUG_LEVEL >= 2 + __get_db()->__insert_c(this); +#endif  __table_.rehash(__n);  insert(__il.begin(), __il.end());  }